home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume11 / mush5.7 / part07 < prev    next >
Encoding:
Internet Message Format  |  1987-09-17  |  43.4 KB

  1. Subject:  v11i057:  Mail user's shell, Part07/12
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: island!argv@Sun.COM (Dan Heller)
  7. Posting-number: Volume 11, Issue 57
  8. Archive-name: mush5.7/Part07
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 7 (of 12)."
  17. # Contents:  commands.c misc.c
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. if test -f 'commands.c' -a "${1}" != "-c" ; then 
  20.   echo shar: Will not clobber existing file \"'commands.c'\"
  21. else
  22. echo shar: Extracting \"'commands.c'\" \(19548 characters\)
  23. sed "s/^X//" >'commands.c' <<'END_OF_FILE'
  24. X/* @(#)cmds.c    (c) copyright 10/18/86 (Dan Heller) */
  25. X
  26. X#include "mush.h"
  27. X
  28. X/*
  29. X * Note that all of the routines in here act upon and return 0 or -1.
  30. X * if -1, then the main loop will clear message lists.
  31. X */
  32. X
  33. Xstruct cmd cmds[] = {
  34. X#ifdef SIGSTOP
  35. X    { "stop", stop },
  36. X#endif SIGSTOP
  37. X    { "?",       question_mark },{ "sh", sh },
  38. X    { "alias",       do_alias    },  { "unalias",    do_alias   },
  39. X    { "expand",      do_alias    },  { "cmd",     do_alias   },
  40. X    { "uncmd",       do_alias    },  { "from",    do_from    },
  41. X    { "un_hdr",      do_alias    },  { "my_hdr",      do_alias   },
  42. X    { "fkey",       do_alias    },  { "unfkey",     do_alias   },
  43. X    { "set",       set         },  { "unset",     set        },
  44. X    { "ignore",      set         },  { "unignore", set        },
  45. X    { "version",  do_version  },  { "help",    print_help },
  46. X    { "pick",       do_pick     },  { "sort",     sort        },
  47. X    { "next",      readmsg     },  { "previous", readmsg    },
  48. X    { "type",     readmsg     },  { "print",    readmsg    },
  49. X    { "history",  disp_hist   },  { "top",    readmsg       },
  50. X    { "saveopts", save_opts   },  { "source",   source        },
  51. X    { "headers",  do_hdrs     },  { "ls",    ls       },
  52. X    { "folder",   folder      },  { "update",   folder     },
  53. X    { "cd",       cd          },  { "pwd",    cd        },
  54. X    { "exit",      quit        },  { "quit",     quit        },
  55. X    { "write",       save_msg    },  { "save",     save_msg   },
  56. X    { "copy",       save_msg    },  { "folders",  folders    },
  57. X#ifdef CURSES
  58. X    { "curses",   curses_init },  { "bind", bind_it   }, { "unbind", bind_it },
  59. X#endif CURSES
  60. X    { "preserve", preserve    },  { "unpreserve",  preserve   },
  61. X    { "replyall", respond     },  { "replysender", respond    },
  62. X    { "delete",      delete      },  { "undelete",    delete     },
  63. X    { "mail",       do_mail     },  { "echo",       do_echo    },
  64. X    { "lpr",       lpr           },  { "alternates",  alts       },
  65. X    { NULL, quit }
  66. X};
  67. X
  68. Xstruct cmd ucb_cmds[] = {
  69. X    { "t",   readmsg   }, { "n",  readmsg  }, { "p", readmsg  },
  70. X    { "+",   readmsg   }, { "-", readmsg   },
  71. X    { "x",   quit      }, { "q",  quit     },
  72. X    { ":a",  do_hdrs   }, { ":d", do_hdrs  },
  73. X    { ":o",  do_hdrs   }, { ":u", do_hdrs  }, { ":n", do_hdrs },
  74. X    { "z",   do_hdrs   }, { "z-", do_hdrs  }, { "z+", do_hdrs },
  75. X    { "h",   do_hdrs   }, { "H",  do_hdrs  },
  76. X    { "f",   do_from   }, { "m",  do_mail  }, { "alts", alts  },
  77. X    { "d",   delete    }, { "dt", delete   }, { "dp", delete  },
  78. X    { "u",   delete    }, { "fo", folder   },
  79. X    { "s",   save_msg  }, { "co", save_msg },
  80. X    { "pre", preserve  }, { "w",  save_msg },
  81. X    { "R",   respond   }, { "r",   respond },
  82. X    { "reply", respond }, { "respond", respond },
  83. X    { NULL, quit }
  84. X};
  85. X
  86. Xstruct cmd hidden_cmds[] = {
  87. X    { "debug", toggle_debug }, { "open",     nopenfiles },
  88. X    { "flags", msg_flags    }, { "stty",    my_stty    },
  89. X    { "setenv",    Setenv      }, { "unsetenv",     Unsetenv   },
  90. X    { "printenv", Printenv  },
  91. X    { NULL, quit }
  92. X};
  93. X
  94. Xtoggle_debug(argc, argv)
  95. Xchar **argv;
  96. X{
  97. X    if (argc < 2) /* no value -- toggle "debug" (off/on) */
  98. X    debug = !debug;
  99. X    else
  100. X    debug = atoi(*++argv);
  101. X    print("debugging value: %d\n", debug);
  102. X    return -1;
  103. X}
  104. X
  105. Xstatic
  106. Xsorter(cmd1, cmd2)
  107. Xregister struct cmd *cmd1, *cmd2;
  108. X{
  109. X    return strcmp(cmd1->command, cmd2->command);
  110. X}
  111. X
  112. Xsort_commands()
  113. X{
  114. X    qsort((char *)cmds, sizeof(cmds)/sizeof(struct cmd)-1,
  115. X            sizeof(struct cmd), sorter);
  116. X}
  117. X
  118. X/* if + was specified, then print messages without headers.
  119. X * n or \n (which will be NULL) will print next unread or undeleted message.
  120. X */
  121. Xreadmsg(x, argv, list)
  122. Xregister char **argv, list[];
  123. X{
  124. X    register char *p = x? *argv : NULL;
  125. X    register long flg = 0;
  126. X
  127. X    if (x && *++argv && !strcmp(*argv, "-?"))
  128. X    return help(0, "readmsg", cmd_help);
  129. X#ifdef NOT_NOW
  130. X    if (ison(glob_flags, IS_GETTING)) {
  131. X    print("Finish editing your letter first.\n");
  132. X    return -1;
  133. X    }
  134. X#endif NOT_NOW
  135. X    if (!msg_cnt) {
  136. X    print("No messages.\n");
  137. X    return -1;
  138. X    }
  139. X    if (x && !strcmp(p, "top"))
  140. X    turnon(flg, TOP);
  141. X    if (p && (*p == '+')) {
  142. X    turnon(flg, NO_PAGE);
  143. X    turnon(flg, NO_HEADER);
  144. X    }
  145. X    if (x && (x = get_msg_list(argv, list)) == -1)
  146. X    return -1;
  147. X    else if (x == 0) {  /* no arguments were parsed (or given) */
  148. X    /* get_msg_list sets current msg on */
  149. X    unset_msg_bit(list, current_msg);
  150. X    /* most commands move to the "next" message. type and print don't */
  151. X    if ((!p || !*p || *p == 'n' || *p == '+') && current_msg < msg_cnt &&
  152. X                    isoff(msg[current_msg].m_flags, UNREAD))
  153. X        current_msg++;
  154. X    if (p && (*p == '-' || !strcmp(p, "previous"))) {
  155. X        while (--current_msg >= 0 && ison(msg[current_msg].m_flags, DELETE))
  156. X        ;
  157. X        if (current_msg < 0) {
  158. X        print("No previous message.\n");
  159. X        current_msg = 0;
  160. X        return -1;
  161. X        }
  162. X    } else {
  163. X        /*
  164. X         * To be compatible with ucb-mail, find the next available unread
  165. X         * message.  Stop at the end (don't wrap). Not the greatest way to
  166. X         * do it, but people complain if it doesn't do it.
  167. X         */
  168. X#ifdef NOT_ANYMORE
  169. X        if (current_msg == msg_cnt) /* wrap around */
  170. X        current_msg = 0;
  171. X#endif NOT_ANYMORE
  172. X        /* "type" or "print" prints the current only -- "next" goes on.. */
  173. X        if (!p || !*p || *p == 'n')
  174. X        while (current_msg < msg_cnt &&
  175. X            ison(msg[current_msg].m_flags, DELETE))
  176. X            current_msg++;
  177. X        if (current_msg >= msg_cnt) {
  178. X        print("No more messages.\n");
  179. X        current_msg = msg_cnt - 1;
  180. X        return -1;
  181. X        }
  182. X    }
  183. X    set_msg_bit(list, current_msg);
  184. X    }
  185. X    /* If we're piping messages, just return the message list */
  186. X    if (ison(glob_flags, DO_PIPE))
  187. X    return 0;
  188. X    current_msg = 0;
  189. X    for (x = 0; x < msg_cnt; x++)
  190. X    if (msg_bit(list, x)) {
  191. X        current_msg = x;
  192. X#ifdef SUNTOOL
  193. X        if (istool > 1) {
  194. X        read_mail(NO_ITEM, 0, NO_EVENT);
  195. X        return 0;
  196. X        }
  197. X#endif SUNTOOL
  198. X        display_msg(x, flg);
  199. X    }
  200. X    return 0;
  201. X}
  202. X
  203. Xpreserve(n, argv, list)
  204. Xregister int n;        /* no use for argc, so use space for a local variable */
  205. Xregister char **argv, list[];
  206. X{
  207. X    register int unpre;
  208. X
  209. X    unpre = !strncmp(*argv, "un", 2);
  210. X    if (*++argv && !strcmp(*argv, "-?"))
  211. X    return help(0, "preserve_help", cmd_help);
  212. X    if (get_msg_list(argv, list) == -1)
  213. X    return -1;
  214. X    for (n = 0; n < msg_cnt; n++)
  215. X    if (msg_bit(list, n))
  216. X        if (unpre)
  217. X        turnoff(msg[n].m_flags, PRESERVE);
  218. X        else {
  219. X        turnon(msg[n].m_flags, PRESERVE);
  220. X        turnoff(msg[n].m_flags, DELETE);
  221. X        }
  222. X    if (istool)
  223. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  224. X    return 0;
  225. X}
  226. X
  227. Xlpr(n, argv, list)
  228. Xregister int n;  /* no use for argc, so use its address space for a variable */
  229. Xregister char **argv, list[];
  230. X{
  231. X    register FILE    *pp;
  232. X    register long     flags = 0;
  233. X    char        print_cmd[128], *printer, c, *cmd;
  234. X    int            total = 0, (*oldint)(), (*oldquit)();
  235. X
  236. X    turnon(flags, NO_IGNORE);
  237. X    if (!(printer = do_set(set_options, "printer")) || !*printer)
  238. X    printer = DEF_PRINTER;
  239. X    while (argv && *++argv && **argv == '-') {
  240. X    n = 1;
  241. X    while (c = argv[0][n++])
  242. X        switch(c) {
  243. X        case 'n': turnon(flags, NO_HEADER);
  244. X        when 'h': turnoff(flags, NO_IGNORE);
  245. X        when 'P': case 'd':
  246. X            if (!argv[0][n]) {
  247. X                print("specify printer!\n");
  248. X                return -1;
  249. X            }
  250. X            printer = argv[0] + n;
  251. X            n += strlen(printer);
  252. X        otherwise: return help(0, "lpr", cmd_help);
  253. X        }
  254. X    }
  255. X    if (get_msg_list(argv, list) == -1)
  256. X    return -1;
  257. X
  258. X    if (cmd = do_set(set_options, "print_cmd"))
  259. X    (void) strcpy(print_cmd, cmd);
  260. X    else
  261. X#ifdef SYSV
  262. X    (void) sprintf(print_cmd, "%s -d%s", LPR, printer);
  263. X#else
  264. X    (void) sprintf(print_cmd, "%s -P%s", LPR, printer);
  265. X#endif SYSV
  266. X    Debug("print command: %s\n", print_cmd);
  267. X    if (!(pp = popen(print_cmd, "w"))) {
  268. X    error("cannot print");
  269. X    return -1;
  270. X    }
  271. X    on_intr();
  272. X    for (n = 0; isoff(glob_flags, WAS_INTR) && n < msg_cnt; n++) {
  273. X    if (msg_bit(list, n)) {
  274. X        if (total++)
  275. X        fputc('\f', pp); /* send a formfeed for multiple copies */
  276. X        print("printing message %d...", n+1);
  277. X        print_more("(%d lines)\n", copy_msg(n, pp, flags));
  278. X    }
  279. X    }
  280. X    off_intr();
  281. X    (void) pclose(pp);
  282. X    print_more("%d message%s printed ", total, (total==1)? "": "s");
  283. X    if (cmd)
  284. X    print_more("through \"%s\".\n", cmd);
  285. X    else
  286. X    print_more("at \"%s\".\n", printer);
  287. X    return 0;
  288. X}
  289. X
  290. X/* save [msg_list] [file] */
  291. Xsave_msg(n, argv, list)   /* argc isn't used, so use space for variable 'n' */
  292. Xregister char **argv, list[];
  293. X{
  294. X    register FILE    *mail_fp;
  295. X    register char     *file = NULL, *mode, firstchar = **argv, *tmp;
  296. X    int         msg_number, force;
  297. X    long         flg = 0;
  298. X
  299. X    if (*++argv && !strcmp(*argv, "-?"))
  300. X    return help(0, "save_help", cmd_help);
  301. X    if (force = (*argv && !strcmp(*argv, "!")))
  302. X    argv++;
  303. X    if ((n = get_msg_list(argv, list)) == -1)
  304. X    return -1;
  305. X    argv += n;
  306. X    if (*argv && *(file = *argv) == '\\')
  307. X    file++;
  308. X    else if (!file) {
  309. X    /* if no filename specified, save in ~/mbox */
  310. X    if (firstchar == 'w') {
  311. X        /* mbox should have headers. If he really wants it, specify it */
  312. X        print("Must specify file name for 'w'\n");
  313. X        return -1;
  314. X    }
  315. X    if (!(file = do_set(set_options, "mbox")) || !*file)
  316. X        file = DEF_MBOX;
  317. X    }
  318. X    n = 1; /* tell getpath to ignore no such file or directory */
  319. X    tmp = getpath(file, &n);
  320. X    if (n < 0) {
  321. X    print("%s: %s\n", file, tmp);
  322. X    return -1;
  323. X    } else if (n) {
  324. X    print("%s is a directory\n", file);
  325. X    return -1;
  326. X    }
  327. X    file = tmp;
  328. X    if (force || access(file, 0))
  329. X    mode = "w", force = 0;
  330. X    else
  331. X    mode = "a";
  332. X
  333. X    if (!(mail_fp = fopen(file, mode))) {
  334. X    error("cannot save in \"%s\"", file);
  335. X    return -1;
  336. X    }
  337. X#ifdef SUNTOOL
  338. X    if (istool)
  339. X    lock_cursors();
  340. X#endif SUNTOOL
  341. X    turnon(flg, NO_IGNORE);
  342. X    if (firstchar == 'w')
  343. X    turnon(flg, NO_HEADER);
  344. X    else
  345. X    turnon(flg, UPDATE_STATUS);
  346. X    if (do_set(set_options, "keepsave"))
  347. X    firstchar = 'c';
  348. X    for (n = msg_number = 0; msg_number < msg_cnt; msg_number++)
  349. X    if (msg_bit(list, msg_number)) {
  350. X            print("%sing msg %d... ",
  351. X        (firstchar == 's')? "Sav" : "Writ", msg_number+1);
  352. X        print_more("(%d lines)\n", copy_msg(msg_number, mail_fp, flg));
  353. X        /* only mark "deleted" if mailfile is /usr/spool/mail and
  354. X         * we're not "copying.  If keepsave is set, then firstchar
  355. X         * will have already been changed to 'c'
  356. X         */
  357. X        if (is_spool(mailfile) && firstchar != 'c')
  358. X        turnon(msg[msg_number].m_flags, DELETE);
  359. X        n++;
  360. X    }
  361. X    fclose(mail_fp);
  362. X    print_more("%s %d msg%s to %s\n",
  363. X        (*mode == 'a')? "Appended" : "Saved", n, (n != 1)? "s": "", file);
  364. X    if (is_spool(mailfile))
  365. X    turnon(glob_flags, DO_UPDATE);
  366. X#ifdef SUNTOOL
  367. X    if (istool) {
  368. X    unlock_cursors();
  369. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  370. X    }
  371. X#endif SUNTOOL
  372. X    return 0;
  373. X}
  374. X
  375. Xrespond(n, argv, list)
  376. Xregister int n;  /* no use for argc, so use its address space for a variable */
  377. Xregister char **argv, *list;
  378. X{
  379. X    register char *cmd = *argv;
  380. X    char list1[MAXMSGS_BITS];
  381. X
  382. X    if (*++argv && !strcmp(*argv, "-?"))
  383. X    return help(0, "respond_help", cmd_help);
  384. X    if ((n = get_msg_list(argv, list)) == -1)
  385. X    return -1;
  386. X    /* make into our own list so ~: commands don't overwrite this list */
  387. X    bitput(list, list1, MAXMSGS, =);
  388. X    /* back up one arg to replace "cmd" in the new argv[0] */
  389. X    argv += (n-1);
  390. X    if (!strcmp(cmd, "replyall"))
  391. X    Upper(*cmd);
  392. X    strdup(argv[0], cmd);
  393. X    current_msg = -1;
  394. X    for (n = 0; n < msg_cnt; n++)
  395. X    if (msg_bit(list1, n)) {
  396. X        if (current_msg > -1 && istool) {
  397. X        print("tool mode can not respond to multiple messages.");
  398. X        continue;
  399. X        }
  400. X        current_msg = n;
  401. X        set_isread(n);
  402. X        if (do_mail(1, argv) == -1) /* do_mail doesn't look at argc */
  403. X        return -1;
  404. X    }
  405. X    return 0;
  406. X}
  407. X
  408. X/* cd to a particular directory specified by "p" */
  409. Xcd(x, argv) /* argc, unused -- use space for a non-register variable */
  410. Xregister char **argv;
  411. X{
  412. X    char *tmp, cwd[128], *p = argv[1];
  413. X#ifdef SYSV
  414. X    char *getcwd();
  415. X#else
  416. X    char *getwd();
  417. X#endif SYSV
  418. X    int err = 0;
  419. X
  420. X    if (!strcmp(*argv, "pwd")) {
  421. X    p = do_set(set_options, "cwd");
  422. X    if (p && *p) {
  423. X        print("%s\n", p);
  424. X        return -1;
  425. X    }
  426. X    }
  427. X    if (!p || !*p)
  428. X    p = (**argv == 'p')? "." : "~";
  429. X    x = 0;
  430. X    tmp = getpath(p, &x);
  431. X    if (x == -1)
  432. X        print("%s: %s.\n", p, tmp), err++;
  433. X    else if (!x)
  434. X        print("%s: not a directory.\n", tmp), err++;
  435. X    else if (chdir(tmp))
  436. X        error("can't chdir to %s", tmp), err++;
  437. X#ifdef SYSV
  438. X    if (getcwd(cwd, 128) == NULL)
  439. X#else
  440. X    if (getwd(cwd) == NULL)
  441. X#endif SYSV
  442. X    print("can't get cwd: %s.\n", cwd), err++;
  443. X    else {
  444. X    char **new_argv, buf[256];
  445. X    (void) sprintf(buf, "set cwd = \"%s\"", cwd);
  446. X    Debug("%s\n", buf);
  447. X    if (new_argv = mk_argv(buf, &x, 1))
  448. X        (void) add_option(&set_options, new_argv), free_vec(new_argv);
  449. X    }
  450. X    if (istool || iscurses || err) {
  451. X    if (err)
  452. X        turnon(glob_flags, CONT_PRNT);
  453. X    print("Working dir: %s\n", cwd);
  454. X    }
  455. X    return -1;
  456. X}
  457. X
  458. Xquit(argc, argv)
  459. Xchar **argv;
  460. X{
  461. X    if (argc > 1 && !strcmp(argv[1], "-?"))
  462. X     return help(0, "quit_help", cmd_help);
  463. X    if ((!argc || (*argv && **argv == 'q')) && ison(glob_flags, DO_UPDATE)
  464. X    && !copyback())
  465. X    return -1;
  466. X#ifdef CURSES
  467. X    if (iscurses) {
  468. X    /* we may already be on the bottom line; some cases won't be */
  469. X    move(LINES-1, 0), refresh();
  470. X    }
  471. X#endif CURSES
  472. X    cleanup(0);
  473. X#ifdef lint
  474. X    return 0;
  475. X#endif lint
  476. X}
  477. X
  478. Xdelete(argc, argv, list)
  479. Xregister int argc;
  480. Xregister char **argv, list[];
  481. X{
  482. X    register int prnt_next, undel = argc && **argv == 'u';
  483. X
  484. X    prnt_next = (argv && (!strcmp(*argv, "dt") || !strcmp(*argv, "dp")));
  485. X
  486. X    if (argc && *++argv && !strcmp(*argv, "-?")) {
  487. X    print("usage: delete/undelete [msg_list]\n");
  488. X    return -1;
  489. X    }
  490. X
  491. X    if (get_msg_list(argv, list) == -1)
  492. X    return -1;
  493. X    for (argc = 0; argc < msg_cnt; argc++)
  494. X    if (msg_bit(list, argc))
  495. X        if (undel)
  496. X        turnoff(msg[argc].m_flags, DELETE);
  497. X        else
  498. X        turnon(msg[argc].m_flags, DELETE);
  499. X
  500. X    /* only if current_msg has been affected && not in curses mode */
  501. X    if (prnt_next == 0 && !iscurses && msg_bit(list, current_msg))
  502. X    prnt_next = !!do_set(set_options, "autoprint"); /* change to boolean */
  503. X
  504. X    turnon(glob_flags, DO_UPDATE);
  505. X
  506. X    /* goto next available message if current was just deleted.
  507. X     * If there are no more messages, turnoff prnt_next.
  508. X     */
  509. X    if (!iscurses && !undel && ison(msg[current_msg].m_flags, DELETE) &&
  510. X                !next_msg(FALSE, DELETE) && prnt_next)
  511. X        prnt_next = 0;
  512. X
  513. X    if (prnt_next)
  514. X    display_msg(current_msg, (long)0);
  515. X    if (istool)
  516. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  517. X    return 0;
  518. X}
  519. X
  520. X/*
  521. X * historically from the "from" command in ucb-mail, this just prints
  522. X * the composed header of the messages set in list or in pipe.
  523. X */
  524. Xdo_from(n, argv, list)
  525. Xchar **argv, list[];
  526. X{
  527. X    int inc_cur_msg = 0;
  528. X
  529. X    if (argv && *++argv && !strcmp(*argv, "-?"))
  530. X    return help(0, "from", cmd_help);
  531. X    if (argv && *argv && (!strcmp(*argv, "+") || !strcmp(*argv, "-")))
  532. X    if (!strcmp(*argv, "+")) {
  533. X        if (!*++argv && current_msg < msg_cnt-1)
  534. X        current_msg++;
  535. X        inc_cur_msg = 1;
  536. X    } else if (!strcmp(*argv, "-")) {
  537. X        if (!*++argv && current_msg > 0)
  538. X        current_msg--;
  539. X        inc_cur_msg = -1;
  540. X    }
  541. X    if (get_msg_list(argv, list) == -1)
  542. X    return -1;
  543. X    for (n = 0; n < msg_cnt; n++)
  544. X    if (msg_bit(list, n)) {
  545. X        wprint("%s\n", compose_hdr(n));
  546. X        /* if -/+ given, set current message pointer to this message */
  547. X        if (inc_cur_msg) {
  548. X        current_msg = n;
  549. X        /* if - was given, then set to first listed message.
  550. X         * otherwise, + means last listed message -- let it go...
  551. X         */
  552. X        if (inc_cur_msg < 0)
  553. X            inc_cur_msg = 0;
  554. X        }
  555. X    }
  556. X    return 0;
  557. X}
  558. X
  559. X/*
  560. X * Do an ls from the system.
  561. X * Read from a popen and use wprint in case the tool does this command.
  562. X * The folders command uses this command.
  563. X */
  564. Xls(x, argv)
  565. Xchar **argv;
  566. X{
  567. X    register char  *p, *tmp;
  568. X    char       buf[128];
  569. X    register FILE  *pp;
  570. X
  571. X    if (*++argv && !strcmp(*argv, "-?"))
  572. X    return help(0, "ls", cmd_help);
  573. X    if (!(p = do_set(set_options, "lister")))
  574. X    p = "";
  575. X    (void) sprintf(buf, "%s -C%s ", LS_COMMAND, p);
  576. X    p = buf+strlen(buf);
  577. X    for ( ; *argv; ++argv) {
  578. X    x = 0;
  579. X    if (**argv != '-')
  580. X        tmp = getpath(*argv, &x);
  581. X    else
  582. X        tmp = *argv;
  583. X    if (x == -1) {
  584. X        wprint("%s: %s\n", *argv, tmp);
  585. X        return -1;
  586. X    }
  587. X    p += strlen(sprintf(p, " %s", tmp));
  588. X    }
  589. X    if (!(pp = popen(buf, "r"))) {
  590. X    error(buf);
  591. X    return -1;
  592. X    }
  593. X    turnon(glob_flags, IGN_SIGS);
  594. X    while (fgets(buf, 127, pp))
  595. X    wprint(buf);
  596. X    (void) pclose(pp);
  597. X    turnoff(glob_flags, IGN_SIGS);
  598. X    return 0;
  599. X}
  600. X
  601. Xsh(un_used, argv)
  602. Xchar **argv;
  603. X{
  604. X    register char *p;
  605. X    char buf[128];
  606. X
  607. X    if (istool > 1 || *++argv && !strcmp(*argv, "-?"))
  608. X    return help(0, "shell", cmd_help);
  609. X    if (!(p = do_set(set_options, "shell"))
  610. X    && !(p = do_set(set_options, "SHELL")))
  611. X    p = DEF_SHELL;
  612. X    if (!*argv)
  613. X    (void) strcpy(buf, p);
  614. X    else
  615. X    (void) argv_to_string(buf, argv);
  616. X    echo_on();
  617. X    (void) system(buf);
  618. X    echo_off();
  619. X    return 0;
  620. X}
  621. X
  622. Xquestion_mark(x, argv)
  623. Xchar **argv;
  624. X{
  625. X    int n = 0;
  626. X    char *Cmds[50], *p, *malloc(), buf[30];
  627. X
  628. X    if (!*++argv) {
  629. X    for (x = 0; cmds[x].command; x++) {
  630. X        if (!(x % 5))
  631. X        if (!(p = Cmds[n++] = malloc(80))) {
  632. X            error("malloc in question_mark()");
  633. X            free_vec(Cmds);
  634. X            return -1;
  635. X        }
  636. X        p += strlen(sprintf(p, "%-11.11s  ", cmds[x].command));
  637. X    }
  638. X    Cmds[n++] = savestr("Type: `command' -? for help with most commands.");
  639. X    Cmds[n] = NULL;
  640. X    (void) help(0, Cmds, NULL);
  641. X    free_vec(Cmds);
  642. X    } else {
  643. X    for (x = 0; cmds[x].command; x++)
  644. X        if (!strcmp(*argv, cmds[x].command))
  645. X        return cmd_line(sprintf(buf, "%s -?", *argv), msg_list);
  646. X    print("Unknown command: %s\n", *argv);
  647. X    }
  648. X    return -1;
  649. X}
  650. X
  651. X#ifdef SIGSTOP
  652. Xstop(argc, argv)
  653. Xchar **argv;
  654. X{
  655. X    if (istool)
  656. X    print("Not a tool-based option.");
  657. X    if (argc && *++argv && !strcmp(*argv, "-?"))
  658. X    return help(0, "stop", cmd_help);
  659. X    if (kill(getpid(), SIGTSTP) == -1)
  660. X    error("couldn't stop myself");
  661. X    return -1;
  662. X}
  663. X#endif SIGSTOP
  664. X
  665. Xextern char **environ;
  666. Xstatic int spaces = 0;
  667. X
  668. XSetenv(i, argv)
  669. Xchar **argv;
  670. X{
  671. X    char *newstr;
  672. X
  673. X    if (i < 2 || i > 3 || !strcmp(argv[1], "-?"))
  674. X    return help(0, "setenv", cmd_help);
  675. X
  676. X    if (i == 3) {
  677. X    newstr = malloc(strlen(argv[1]) + strlen(argv[2]) + 2);
  678. X    (void) sprintf(newstr, "%s=%s", argv[1], argv[2]);
  679. X    } else {
  680. X    newstr = malloc(strlen(argv[1]) + 2);
  681. X    (void) sprintf(newstr, "%s=", argv[1]);
  682. X    }
  683. X
  684. X    (void) Unsetenv(2, argv);
  685. X
  686. X    for (i = 0; environ[i]; i++);
  687. X    if (!spaces) {
  688. X    char **new_environ = (char **)malloc((i+2) * sizeof(char *));
  689. X    /* add 1 for the new item, and 1 for null-termination */
  690. X    if (!new_environ) {
  691. X        free(newstr);
  692. X        return -1;
  693. X    }
  694. X    spaces = 1;
  695. X    for (i = 0; new_environ[i] = environ[i]; i++);
  696. X    xfree(environ);
  697. X    environ = new_environ;
  698. X    }
  699. X    environ[i] = newstr;
  700. X    environ[i+1] = NULL;
  701. X    spaces--;
  702. X    return -1;
  703. X}
  704. X
  705. XUnsetenv(n, argv)
  706. Xchar **argv;
  707. X{
  708. X    char **envp, **last;
  709. X
  710. X    if (n != 2 || !strcmp(argv[1], "-?"))
  711. X    return help(0, "unsetenv", cmd_help);
  712. X
  713. X    n = strlen(argv[1]);
  714. X    for (last = environ; *last; last++);
  715. X    last--;
  716. X
  717. X    for (envp = environ; envp <= last; envp++) {
  718. X    if (strncmp(argv[1], *envp, n) == 0 && (*envp)[n] == '=') {
  719. X        xfree(*envp);
  720. X        *envp = *last;
  721. X        *last-- = NULL;
  722. X        spaces++;
  723. X    }
  724. X    }
  725. X    return -1;
  726. X}
  727. X
  728. XPrintenv()
  729. X{
  730. X    char **e = environ;
  731. X    while (*e)
  732. X    wprint("%s\n", *e++);
  733. X    return -1;
  734. X}
  735. X
  736. X/*
  737. X * internal stty call to allow the user to change his tty character
  738. X * settings.  sorry, no way to change cbreak/echo modes.  Save echo_flg
  739. X * so that execute() won't reset it.
  740. X */
  741. Xmy_stty(un_used, argv)
  742. Xchar **argv;
  743. X{
  744. X    long save_echo = ison(glob_flags, ECHO_FLAG);
  745. X
  746. X    turnon(glob_flags, ECHO_FLAG);
  747. X    execute(argv);
  748. X    if (save_echo)
  749. X    turnon(glob_flags, ECHO_FLAG);
  750. X    else
  751. X    turnoff(glob_flags, ECHO_FLAG);
  752. X
  753. X    savetty();
  754. X#ifdef TIOCGLTC
  755. X    if (ioctl(0, TIOCGLTC, <chars))
  756. X    error("TIOCGLTC");
  757. X#endif TIOCGLTC
  758. X    echo_off();
  759. X    return -1;
  760. X}
  761. END_OF_FILE
  762. if test 19548 -ne `wc -c <'commands.c'`; then
  763.     echo shar: \"'commands.c'\" unpacked with wrong size!
  764. fi
  765. # end of 'commands.c'
  766. fi
  767. if test -f 'misc.c' -a "${1}" != "-c" ; then 
  768.   echo shar: Will not clobber existing file \"'misc.c'\"
  769. else
  770. echo shar: Extracting \"'misc.c'\" \(21487 characters\)
  771. sed "s/^X//" >'misc.c' <<'END_OF_FILE'
  772. X/* @(#)misc.c    (c) copyright 10/18/86 (Dan Heller) */
  773. X
  774. X#include "mush.h"
  775. X
  776. X/* check to see if a string describes a message that is within the range of
  777. X * all messages; if invalid, return 0 and print error. else return msg number
  778. X */
  779. Xchk_msg(s)
  780. Xregister char *s;
  781. X{
  782. X    register int n;
  783. X
  784. X    if ((n = atoi(s)) > 0 && n <= msg_cnt)
  785. X    return n;
  786. X    else if (*s == '^' && msg_cnt)
  787. X    return 1;
  788. X    else if (*s == '$' && msg_cnt)
  789. X    return msg_cnt;
  790. X    else if (*s == '.' && msg_cnt)
  791. X    return current_msg+1;
  792. X    print("Invalid message number: %s\n", s);
  793. X    return 0;
  794. X}
  795. X
  796. X/*
  797. X * loop thru all msgs starting with current_msg and find next message whose
  798. X * m_flags has the "flags" bit being on
  799. X */
  800. Xnext_msg(on, flags)
  801. X{
  802. X    register int n = current_msg;
  803. X    if (!msg_cnt)
  804. X    return current_msg = 0;
  805. X    for (n++; n != current_msg; n++)
  806. X    if (n == msg_cnt)     /* hit the end, start back at the beginning */
  807. X        n = -1; /* increments to 0 in  loop  */
  808. X    else if (isoff(msg[n].m_flags, DELETE) &&
  809. X        ((on && ison(msg[n].m_flags, flags)) ||
  810. X        (!on && isoff(msg[n].m_flags, flags))))
  811. X        return current_msg = n;
  812. X    return current_msg = 0;
  813. X}
  814. X
  815. X/* takes string 'p' and address of int (isdir).  If p uses the ~ to reference
  816. X * a home directory of somesort, then expand it.  find out what sort of
  817. X * file final path is. set isidr to 1 if a directory, 0 if not, -1 on error
  818. X * return final path. If an error occurrs, return string indicating error.
  819. X * if isdir has a value of 1 when passed, it ignores "No such file or directory"
  820. X */
  821. X#include <pwd.h>
  822. Xchar *
  823. Xgetpath(p, isdir)
  824. Xregister char *p;
  825. Xint *isdir;
  826. X{
  827. X    static char buf[256];
  828. X    struct stat stat_buf;
  829. X
  830. X    if (!p || !*p || !strcmp(p, "~")) {
  831. X    char *home = do_set(set_options, "home");
  832. X    if (!home || !*home)
  833. X        home = ALTERNATE_HOME;
  834. X    (void) strcpy(buf, home);  /* no arg means home */
  835. X    } else if (*p == '~') {
  836. X    if (p[1] != '/') {
  837. X        /* not our home, but someone else's
  838. X         * look for ~user or ~user/subpath
  839. X         * if '/' exists, separate into tmp="user" p="subpath"
  840. X         */
  841. X        struct passwd *ent, *getpwnam();
  842. X        char *p2 = p+1;
  843. X        if (p = index(p2, '/'))
  844. X        *p++ = 0;
  845. X        if (!(ent = getpwnam(p2))) {
  846. X        *isdir = -1;
  847. X        return sprintf(buf, "no such user: %s", p2);
  848. X        }
  849. X        /* append subpath to pathname */
  850. X        if (p && *p)
  851. X        (void) sprintf(buf, "%s/%s", ent->pw_dir, p);
  852. X        /* if *p == NULL, pathname is done (buf), set isdir = 1 */
  853. X        else {
  854. X        *isdir = 1;
  855. X        return strcpy(buf, ent->pw_dir);
  856. X        }
  857. X    } else {
  858. X        char *home = do_set(set_options, "home");
  859. X        if (!home || !*home)
  860. X        home = ALTERNATE_HOME;
  861. X        (void) sprintf(buf, "%s/%s", home, p+2);
  862. X    }
  863. X    } else if (*p == '%') {
  864. X    /* if %user, append user name... else, it's just us */
  865. X    (void) sprintf(buf, "%s/", MAILDIR);
  866. X    if (!*++p || *p == ' ' || *p == '\t')
  867. X        (void) strcat(buf, login);
  868. X    else
  869. X        (void) strcat(buf, p);
  870. X    } else if (*p == '+') {
  871. X    register char *p2 = do_set(set_options, "folder");
  872. X    if (p2 && *p2)
  873. X        (void) sprintf(buf, "%s/%s", p2, ++p);
  874. X    else
  875. X        (void) sprintf(buf, "~/%s", p);
  876. X    if (*buf == '~') {
  877. X        int t_isdir = *isdir;
  878. X        char *t, tmp[256];
  879. X        (void) strcpy(tmp, buf);
  880. X        t = getpath(tmp, &t_isdir);
  881. X        if (t_isdir == -1) {
  882. X        *isdir = -1;
  883. X        return t;
  884. X        }
  885. X        /* strcpy(buf, t); --buf already has info because it's static */
  886. X    }
  887. X    } else {  /* allow \ to escape the special chars, +, %, ~ */
  888. X    if (*p == '\\')
  889. X        p++;
  890. X    (void) strcpy(buf, p);
  891. X    }
  892. X    if (stat(buf, &stat_buf)) {
  893. X    (void) access(buf, 0); /* set errno to the "real" reason */
  894. X    if (errno == ENOENT && *isdir == 1) {
  895. X        *isdir = 0; /* say it's a regular file even tho it doesn't exist */
  896. X        return buf; /* it may be wanted for creating */
  897. X    }
  898. X    *isdir = -1;
  899. X    return sys_errlist[errno];
  900. X    }
  901. X    *isdir = ((stat_buf.st_mode & S_IFDIR) != 0);
  902. X    return buf;
  903. X}
  904. X
  905. X/*
  906. X * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp
  907. X * opens the file with the mode.
  908. X * If the mode is "r" then we read the file into the file pointer at the
  909. X * end (fseek(fp, 2, 0)).  If the file is opened for writing, then read
  910. X * from the beginning of fp and write it into the file.
  911. X * This is usually called to read .signatures into messages (thus,
  912. X * opening .signture with "r" and writing to the end of fp which is probably
  913. X * the sendmail process or the message file pointer) or to write fortunes into
  914. X * the message buffer: reading fp (the popened fortune) and writing into file.
  915. X */
  916. Xvoid
  917. Xfile_to_fp(p, fp, mode)
  918. Xregister char *p;
  919. Xregister FILE *fp;
  920. Xchar *mode;
  921. X{
  922. X    int     x = 1;
  923. X    char     *file, buf[BUFSIZ];
  924. X    FILE     *tmp_fp;
  925. X
  926. X    if (!p || !*p) {
  927. X    print("specify filename");
  928. X    return;
  929. X    }
  930. X    file = getpath(p, &x);
  931. X    if (x == -1) { /* on error, file contains error message */
  932. X    wprint(file);
  933. X    return;
  934. X    }
  935. X    wprint("%s: ", file), fflush(stdout);
  936. X    if (x)   /* if x == 1, then path is a directory */
  937. X    wprint("directory.\n");
  938. X    else if (!(tmp_fp = fopen(file, mode))) {
  939. X    wprint("%s\n", sys_errlist[errno]);
  940. X    return;
  941. X    } else if (*mode != 'r') {
  942. X    rewind(fp);
  943. X    for(x = 0; fgets(buf, BUFSIZ, fp); x++)
  944. X        fputs(buf, tmp_fp);
  945. X    } else
  946. X    for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++)
  947. X        fputs(buf, fp);
  948. X    wprint("%s%d line%s\n", (*mode == 'a')? "added ": "",
  949. X                  x, (x == 1)? "": "s");
  950. X    fflush(fp);
  951. X    fclose(tmp_fp);
  952. X}
  953. X
  954. X/*
  955. X * lose the newline character, trailing whitespace, and return the end of p
  956. X * test for '\n' separately since some _ctype_[] arrays may not have the
  957. X * _S bit set for the newline character.  see <ctype.h> for more info.
  958. X */
  959. Xchar *
  960. Xno_newln(p)
  961. Xregister char *p;
  962. X{
  963. X    register char *p2 = p + strlen(p);    /* point it to the null terminator */
  964. X
  965. X    while (p2 > p && *--p2 == '\n' || isspace(*p2))
  966. X    *p2 = 0;  /* get rid of newline and trailing spaces */
  967. X    return p2;
  968. X}
  969. X
  970. X/* find any character in string2 that's in string1 */
  971. Xchar *
  972. Xany(s1, s2)
  973. Xregister char *s1, *s2;
  974. X{
  975. X    register char *p;
  976. X    if (!s1 || !*s1 || !s2 || !*s2)
  977. X    return NULL;
  978. X    for( ; *s1; s1++) {
  979. X    for(p = s2; *p; p++)
  980. X        if (*p == *s1)
  981. X        return s1;
  982. X    }
  983. X    return NULL;
  984. X}
  985. X
  986. X/* since print_help just prints help, always return help() */
  987. Xprint_help(argc, argv)
  988. Xregister char **argv;
  989. X{
  990. X#ifdef SUNTOOL
  991. X    if (istool)
  992. X    return help(tool->tl_windowfd, "general", tool_help);
  993. X#endif SUNTOOL
  994. X    if (!argc || !*++argv)
  995. X    return help(0, "general", cmd_help);
  996. X    return help(0, *argv, cmd_help);
  997. X}
  998. X
  999. X/* since this function does not affect messages, return -1 */
  1000. Xhelp(fd, str, file)
  1001. X#ifdef SUNTOOL
  1002. Xcaddr_t *str;
  1003. X#else
  1004. Xchar *str;
  1005. X#endif /* SUNTOOL */
  1006. Xchar *file;
  1007. X{
  1008. X#ifdef SUNTOOL
  1009. X    if (istool > 1) {
  1010. X    int oldmask;
  1011. X    if (!fd)
  1012. X        fd = print_sw->ts_windowfd;
  1013. X    oldmask = sigblock(1 << ((SIGALRM) - 1));
  1014. X    lock_cursors();
  1015. X    if (display_help(fd, str, file, fonts[LARGE]) && file)
  1016. X        error("can't read %s", file);
  1017. X    unlock_cursors();
  1018. X    (void) sigsetmask(oldmask);
  1019. X    } else
  1020. X#endif SUNTOOL
  1021. X    if (find_help(str, file) && file)
  1022. X    error("can't read %s", file);
  1023. X    return -1; /* doesn't affect any messages */
  1024. X}
  1025. X
  1026. X#ifdef SUNTOOL
  1027. Xvoid
  1028. Xunlock_cursors()
  1029. X{
  1030. X    if (istool < 2)
  1031. X    return;
  1032. X    win_setcursor(print_sw->ts_windowfd, &main_cursor);
  1033. X    win_setcursor(panel_sw->ts_windowfd, &main_cursor);
  1034. X    if (getting_opts)
  1035. X    win_setcursor(msg_sw->ts_windowfd, &checkmark);
  1036. X    else if (ison(glob_flags, IS_GETTING))
  1037. X    win_setcursor(msg_sw->ts_windowfd, &write_cursor);
  1038. X    else
  1039. X    win_setcursor(msg_sw->ts_windowfd, &read_cursor);
  1040. X    win_setcursor(hdr_panel_sw->ts_windowfd, &main_cursor);
  1041. X    win_setcursor(hdr_sw->ts_windowfd, &l_cursor);
  1042. X}
  1043. X
  1044. Xvoid
  1045. Xlock_cursors()
  1046. X{
  1047. X    if (istool < 2)
  1048. X    return;
  1049. X    win_setcursor(hdr_sw->ts_windowfd, &coffee);
  1050. X    win_setcursor(print_sw->ts_windowfd, &coffee);
  1051. X    win_setcursor(panel_sw->ts_windowfd, &coffee);
  1052. X    win_setcursor(msg_sw->ts_windowfd, &coffee);
  1053. X    win_setcursor(hdr_panel_sw->ts_windowfd, &coffee);
  1054. X}
  1055. X
  1056. X#include <suntool/fullscreen.h>
  1057. X/* return the event-id that confirmed */
  1058. Xconfirm(fd)
  1059. X{
  1060. X    struct fullscreen *fs;
  1061. X
  1062. X    struct inputmask im;
  1063. X    struct inputevent event;
  1064. X
  1065. X    fs = fullscreen_init(fd);
  1066. X    input_imnull(&im);
  1067. X    im.im_flags |= IM_ASCII;
  1068. X    win_setinputcodebit(&im, MS_LEFT);
  1069. X    win_setinputcodebit(&im, MS_MIDDLE);
  1070. X    win_setinputcodebit(&im, MS_RIGHT);
  1071. X    win_setinputmask(fd, &im, &im, WIN_NULLLINK);
  1072. X    win_setcursor(fd, &l_cursor);
  1073. X    if (input_readevent(fd, &event) == -1)
  1074. X    error("confim failed");
  1075. X    fullscreen_destroy(fs);
  1076. X    return ID;
  1077. X}
  1078. X#endif SUNTOOL
  1079. X
  1080. X/* check two lists of strings each of which contain substrings.
  1081. X * Each substring is delimited by any char in "delimeters"
  1082. X * return true if any elements in list1 are on list2.
  1083. X * thus:
  1084. X * string1 = "foo, bar, baz"
  1085. X * string2 = "foobar, baz, etc"
  1086. X * delimeters = ", \t"
  1087. X * example returns 1 because "baz" exists in both lists
  1088. X * NOTE: case is ignored.
  1089. X */
  1090. Xchk_two_lists(list1, list2, delimeters)
  1091. Xregister char *list1, *list2, *delimeters;
  1092. X{
  1093. X    register char *p, c;
  1094. X    register int found = 0;
  1095. X
  1096. X    if (p = any(list1, delimeters)) {
  1097. X    for (p++; *p && index(delimeters, *p); p++)
  1098. X        ;
  1099. X    if (chk_two_lists(p, list2, delimeters))
  1100. X        return 1;
  1101. X    }
  1102. X    if (p = any(list2, delimeters)) {
  1103. X    for (p++; *p && index(delimeters, *p); p++)
  1104. X        ;
  1105. X    if (chk_two_lists(list1, p, delimeters))
  1106. X        return 1;
  1107. X    }
  1108. X    if (p) {
  1109. X    while (index(delimeters, *(p-1)))
  1110. X        --p;
  1111. X    c = *p, *p = 0;
  1112. X    }
  1113. X    found = !lcase_strcmp(list1, list2);
  1114. X    if (p)
  1115. X    *p = c;
  1116. X    return found;
  1117. X}
  1118. X
  1119. Xbzero(addr, size)
  1120. Xregister char *addr;
  1121. Xregister int size;
  1122. X{
  1123. X    while (size-- > 0)
  1124. X    addr[size] = 0;
  1125. X}
  1126. X
  1127. X/* see if there are at least Max lines in this file. return lines less than Max
  1128. X * that actually *are* in the file
  1129. X */
  1130. Xlines_in(fp, Max)
  1131. Xregister FILE *fp;
  1132. Xregister int Max;
  1133. X{
  1134. X    char tmp[BUFSIZ];
  1135. X    long place_in_fp = ftell(fp);
  1136. X    rewind(fp);
  1137. X    while (Max > 0 && fgets(tmp, BUFSIZ, fp))
  1138. X    Max--;
  1139. X    (void) fseek(fp, place_in_fp, 0);
  1140. X    return Max;
  1141. X}
  1142. X
  1143. X/* clear all contents of the file.  Careful that the file is opened for
  1144. X * _writing_ --tempfile is opened for reading, so don't try to empty it
  1145. X * if you're using ftruncate.   Return -1 on error, 0 on success.
  1146. X */
  1147. Xemptyfile(fp, fname)
  1148. Xregister FILE **fp;
  1149. Xregister char *fname;
  1150. X{
  1151. X    Debug("Emptying \"%s\"\n", fname);
  1152. X#ifndef SYSV
  1153. X    return ftruncate(fileno(*fp), 0);
  1154. X#else
  1155. X    {
  1156. X    int omask = umask(077), ret;
  1157. X    fclose(*fp);
  1158. X    if (!(*fp = fopen(fname, "w")))
  1159. X        ret = -1;
  1160. X    ret = 0;
  1161. X    (void) umask(omask);
  1162. X    return ret;
  1163. X    }
  1164. X#endif SYSV
  1165. X}
  1166. X
  1167. X/* do an atoi() on the string passed and return in "val" the decimal value.
  1168. X * the function returns a pointer to the location in the string that is not
  1169. X * a digit.
  1170. X */
  1171. Xchar *
  1172. Xmy_atoi(p, val)
  1173. Xregister char *p;
  1174. Xregister int *val;
  1175. X{
  1176. X    if (!p)
  1177. X    return NULL;
  1178. X    *val = 0;
  1179. X    while (isdigit(*p))
  1180. X    *val = (*val) * 10 + *p++ - '0';
  1181. X    return p;
  1182. X}
  1183. X
  1184. X/* strcmp ignoring case */
  1185. Xlcase_strcmp(str1, str2)
  1186. Xregister char *str1, *str2;
  1187. X{
  1188. X    while (*str1 && *str2)
  1189. X    if (lower(*str1) != lower(*str2))
  1190. X        break;
  1191. X    else
  1192. X        str1++, str2++;
  1193. X    return *str1 - *str2;
  1194. X}
  1195. X
  1196. X/* strcpy coverting everything to lower case (arbitrary) to ignore cases */
  1197. Xchar *
  1198. Xlcase_strcpy(dst, src)
  1199. Xregister char *dst, *src;
  1200. X{
  1201. X    register char *s = dst;
  1202. X
  1203. X    /* "lower" is a macro, don't incrment its argument! */
  1204. X    while (*dst++ = lower(*src))
  1205. X    src++;
  1206. X    return s;
  1207. X}
  1208. X
  1209. X/* this strcpy returns number of bytes copied */
  1210. XStrcpy(dst, src)
  1211. Xregister char *dst, *src;
  1212. X{
  1213. X    register int n = 0;
  1214. X    if (!dst || !src)
  1215. X    return 0;
  1216. X    while (*dst++ = *src++)
  1217. X    n++;
  1218. X    return n;
  1219. X}
  1220. X
  1221. Xvoid
  1222. Xxfree(cp)
  1223. Xchar *cp;
  1224. X{
  1225. X    extern char end[];
  1226. X
  1227. X    if (cp >= end && cp < (char *) &cp && debug < 2)
  1228. X    free(cp);
  1229. X}
  1230. X
  1231. Xchar *
  1232. Xsavestr(s)
  1233. Xregister char *s;
  1234. X{
  1235. X    register char *p;
  1236. X    char *malloc();
  1237. X    if (!s)
  1238. X    s = "";
  1239. X    if (!(p = malloc((unsigned) (strlen(s) + 1)))) {
  1240. X    error("out of memory saving %s", s);
  1241. X    return NULL;
  1242. X    }
  1243. X    return strcpy(p, s);
  1244. X}
  1245. X
  1246. Xvoid
  1247. Xfree_vec(argv)
  1248. Xchar **argv;
  1249. X{
  1250. X    register int n;
  1251. X    if (!argv)
  1252. X    return;
  1253. X    for (n = 0; argv[n]; n++)
  1254. X    xfree(argv[n]);
  1255. X    xfree((char *)argv);
  1256. X}
  1257. X
  1258. X/* copy a vector of stirngs into one string -- return the end of the string */
  1259. Xchar *
  1260. Xargv_to_string(p, argv)
  1261. Xregister char *p, **argv;
  1262. X{
  1263. X    register int i;
  1264. X    register char *ptr = p;
  1265. X
  1266. X    *p = 0;
  1267. X    if (!argv[0])
  1268. X    return "";
  1269. X    for (i = 0; argv[i]; i++)
  1270. X    ptr += strlen(sprintf(ptr, "%s ", argv[i]));
  1271. X    *--ptr = 0;   /* get rid of the last space */
  1272. X    return ptr;
  1273. X}
  1274. X
  1275. X/* echo the command line. return -1 cuz no messages are affected */
  1276. Xdo_echo(argc, argv)
  1277. Xregister char **argv;
  1278. X{
  1279. X    char buf[BUFSIZ];
  1280. X    int no_return;
  1281. X
  1282. X    if (argc > 1 && !strcmp(argv[1], "-?")) {
  1283. X    print("usage: %s [-n] ...\n", *argv);
  1284. X    return -1;
  1285. X    }
  1286. X    no_return = *++argv && !strcmp(*argv, "-n");
  1287. X    (void) argv_to_string(buf, argv+no_return);
  1288. X    print("%s%s", buf, (no_return)? "" : "\n");
  1289. X    return -1;
  1290. X}
  1291. X
  1292. X/* return -1 on error or number of arguments in argv that were parsed */
  1293. Xget_msg_list(argv, list)
  1294. Xregister char **argv;
  1295. Xchar list[];
  1296. X{
  1297. X    register char *p2, *p;
  1298. X    char buf[256];
  1299. X    register int n;
  1300. X
  1301. X    if (!msg_cnt) {
  1302. X    print("No messages.\n");
  1303. X    return -1;
  1304. X    }
  1305. X    if (!argv || !*argv) {
  1306. X    if (isoff(glob_flags, IS_PIPE))
  1307. X        set_msg_bit(list, current_msg);
  1308. X    return 0;
  1309. X    }
  1310. X    /* first, stuff argv's args into a single char array buffer */
  1311. X    (void) argv_to_string(buf, argv);
  1312. X    p = buf;
  1313. X    Debug("get_msg_list: parsing: (%s): ", p);
  1314. X    /*
  1315. X     * if do_range returns NULL, an invalid message was specified
  1316. X     */
  1317. X    if (!(p2 = do_range(p, list)))
  1318. X    return -1;
  1319. X    /*
  1320. X     * if p2 == p (and p isn't $ or ^ or .), then no message list was
  1321. X     * specified.  set the current message in such cases if we're not piping
  1322. X     */
  1323. X    if (p2 == p) {
  1324. X    if (*p == '$')
  1325. X        set_msg_bit(list, msg_cnt-1);
  1326. X    else if (*p == '^')
  1327. X        set_msg_bit(list, 0);
  1328. X    else if (*p == '.' || isoff(glob_flags, IS_PIPE))
  1329. X        set_msg_bit(list, current_msg);
  1330. X    } else if (ison(glob_flags, IS_PIPE)) {
  1331. X    print("You can't pipe to a command *and* specifiy a msg_list\n");
  1332. X    return -1;
  1333. X    }
  1334. X    for (n = 0; p2 > p && *argv; n++)
  1335. X    p2 -= (strlen(*argv++)+1);
  1336. X    Debug("parsed %d args\n", n);
  1337. X    return n;
  1338. X}
  1339. X
  1340. Xchar *
  1341. Xitoa(n)
  1342. X{
  1343. X    static char buf[10];
  1344. X    return sprintf(buf, "%d", n);
  1345. X}
  1346. X
  1347. X#ifdef NOT_NEEDED_NOW
  1348. X/* return whether or not this process is in the foreground or background */
  1349. Xforeground()
  1350. X{
  1351. X#ifdef TIOCGPGRP
  1352. X    int tpgrp;    /* short in 4.1, int in 4.2 */
  1353. X
  1354. X    if (ioctl(0, TIOCGPGRP, (char *)&tpgrp))
  1355. X    return 0;
  1356. X    return tpgrp == getpgrp(0);
  1357. X#else
  1358. X    return 1;
  1359. X#endif TIOCGPGRP
  1360. X}
  1361. X#endif NOT_NEEDED_NOW
  1362. X
  1363. X#ifdef SYSV
  1364. Xchar *
  1365. XSprintf(buf, fmt, args)
  1366. Xregister char *buf, *fmt;
  1367. X{
  1368. X    vsprintf(buf, fmt, &args);
  1369. X    return buf;
  1370. X}
  1371. X#endif /* SYSV */
  1372. X
  1373. X/*
  1374. X * Finds out how many file descriptors are opened.  Useful for making sure
  1375. X * no files got opened in subprocedures which were not subsequently closed.
  1376. X */
  1377. Xnopenfiles(argc)
  1378. X{
  1379. X    register int nfiles = 0;
  1380. X#ifdef MAXFILES
  1381. X    register int size = MAXFILES;
  1382. X#else
  1383. X    register int size = getdtablesize();
  1384. X#endif MAXFILES
  1385. X
  1386. X    if (argc < 2)
  1387. X    print("open file descriptors:");
  1388. X    while (--size >= 0)
  1389. X        if (fcntl(size, F_GETFL, 0) != -1) {
  1390. X        if (argc < 2)
  1391. X        print_more(" %d", size);
  1392. X            ++nfiles;
  1393. X        }
  1394. X    if (argc < 2)
  1395. X    print("\n");
  1396. X    return nfiles;
  1397. X}
  1398. X
  1399. X/*
  1400. X * Open a path for writing or appending -- return a FILE pointer.
  1401. X * If program is TRUE, then use popen, not fopen and don't check 
  1402. X * to see if the file is writable.
  1403. X */
  1404. XFILE *
  1405. Xopen_file(p, program)
  1406. Xregister char *p;
  1407. X{
  1408. X    register FILE *newfile = NULL_FILE;
  1409. X    register char *tmp;
  1410. X    int x = 1;
  1411. X
  1412. X    tmp = getpath(p, &x);
  1413. X    if (x == 1)
  1414. X    print("%s is a directory.\n", tmp);
  1415. X    else if (x == -1)
  1416. X    print("%s: %s\n", p, tmp);
  1417. X    else {
  1418. X    register char *mode = NULL;
  1419. X    /* if it doesn't exist open for "w" */
  1420. X    if (program || access(tmp, 0))
  1421. X        mode = "w";
  1422. X    /* if we can't write to it, forget it */
  1423. X    else if (access(tmp, 2))
  1424. X        error(tmp);
  1425. X    else
  1426. X        mode = "a";
  1427. X    if (mode)
  1428. X        if (program) {
  1429. X        if (!(newfile = popen(tmp, mode))) {
  1430. X            error("Can't execute %s\n", tmp);
  1431. X            return newfile;
  1432. X        }
  1433. X        } else
  1434. X        if (!(newfile = fopen(tmp, mode)))
  1435. X            error("Can't write to %s", tmp);
  1436. X        else
  1437. X        Debug("Successfully opened %s\n", tmp);
  1438. X    }
  1439. X    return newfile;
  1440. X}
  1441. X
  1442. X/*
  1443. X * find_files gets a string of space/comma delimeted words and an array of
  1444. X * file pointers and the maximum size that array can be.
  1445. X * The object is to find the files or programs listed in "p", attempt
  1446. X * to fopen/popen them and save their filepointers in the array. If the
  1447. X * size is 0, then just extract the file names and give error messages
  1448. X * for each one since they will not be opened. Return the number of
  1449. X * files opened and delete all files (opened or not) from the list in
  1450. X * "p".  Tokens beginning with a "/, ~, or + are files; tokens beginning
  1451. X * with a | are programs.
  1452. X */
  1453. Xfind_files(p, files, size)
  1454. Xregister char *p;
  1455. XFILE *files[];
  1456. X{
  1457. X    register int     total = 0;
  1458. X    char          file[BUFSIZ], *start = p;
  1459. X    register char    *p2, *s;
  1460. X
  1461. X    for (s = p; p = any(s, "~+/|"); s = p) {
  1462. X    int prog = 0;
  1463. X
  1464. X    /* If there is no space or comma before this address, then
  1465. X     * it's not the beginning of an address, but part of another.
  1466. X     * Ignore this addres and continue to the next in the list.
  1467. X     */
  1468. X    if (p > start && *(p-1) != ',' && !isspace(*(p-1))) {
  1469. X        p++; /* prevent inifinite loop -- resume starting at next char */
  1470. X        continue;
  1471. X    }
  1472. X
  1473. X    /* get the whole filename, stick it in "file" */
  1474. X    if (p2 = any(p, ", \t"))
  1475. X        *p2++ = '\0';
  1476. X    else
  1477. X        p2 = p + strlen(p);
  1478. X    (void) strcpy(file, p);
  1479. X    /* overwrite the filename in the string with whatever proceeds it */
  1480. X    while (isspace(*p2)) /* move to the next address (or end of string) */
  1481. X        p2++;
  1482. X    if (*p2)
  1483. X        (void) strcpy(p, p2);
  1484. X    else
  1485. X        do
  1486. X        *p = '\0';
  1487. X        while (--p >= start && (isspace(*p) || *p == ','));
  1488. X
  1489. X    if (*file == '|')
  1490. X        prog = 1; /* it's a program name */
  1491. X    if (size && total < size) {
  1492. X        /* either open "file" or &file[1] */
  1493. X        if (files[total] = open_file(&file[prog], prog))
  1494. X        total++;
  1495. X    } else
  1496. X        print("No open space for %s\n", file);
  1497. X    skipspaces(0);
  1498. X    }
  1499. X    return total;
  1500. X}
  1501. X
  1502. X/*
  1503. X * execute a command from a string.  f'rinstance: "pick -f foobar"
  1504. X * The string is made into an argv and then run.  Errors are printed
  1505. X * if the command failed to make.
  1506. X *   NOTES:
  1507. X *     NEVER pass stright text: e.g. "pick -f foobar", ALWAYS strcpy(buf, "...")
  1508. X *     no history is expanded (ignore_bang).
  1509. X */
  1510. Xcmd_line(buf, list)
  1511. Xchar buf[], list[];
  1512. X{
  1513. X    register char **argv;
  1514. X    int argc, ret_val = -1;
  1515. X    long save_bang = ison(glob_flags, IGN_BANG);
  1516. X    long save_do_pipe = ison(glob_flags, DO_PIPE);
  1517. X    long save_is_pipe = ison(glob_flags, IS_PIPE);
  1518. X
  1519. X    turnon(glob_flags, IGN_BANG);
  1520. X    turnoff(glob_flags, DO_PIPE);
  1521. X    turnoff(glob_flags, IS_PIPE);
  1522. X    if (argv = make_command(buf, TRPL_NULL, &argc))
  1523. X    ret_val = do_command(argc, argv, list);
  1524. X    if (!save_bang)
  1525. X    turnoff(glob_flags, IGN_BANG);
  1526. X    if (save_do_pipe)
  1527. X    turnon(glob_flags, DO_PIPE);
  1528. X    if (save_is_pipe)
  1529. X    turnon(glob_flags, IS_PIPE);
  1530. X    return ret_val;
  1531. X}
  1532. X
  1533. Xglob_test(s)
  1534. Xchar *s;
  1535. X{
  1536. X    print("%s: glob_flags =", s);
  1537. X    if (ison(glob_flags, DO_UPDATE))
  1538. X    print_more(" DO_UPDATE");
  1539. X    if (ison(glob_flags, REV_VIDEO))
  1540. X    print_more(" REV_VIDEO");
  1541. X    if (ison(glob_flags, CONT_PRNT  ))
  1542. X    print_more(" CONT_PRNT");
  1543. X    if (ison(glob_flags, DO_SHELL    ))
  1544. X    print_more(" DO_SHELL");
  1545. X    if (ison(glob_flags, DO_PIPE))
  1546. X    print_more(" DO_PIPE");
  1547. X    if (ison(glob_flags, IS_PIPE))
  1548. X    print_more(" IS_PIPE");
  1549. X    if (ison(glob_flags, IGN_SIGS))
  1550. X    print_more(" IGN_SIGS");
  1551. X    if (ison(glob_flags, IGN_BANG))
  1552. X    print_more(" IGN_BANG");
  1553. X    if (ison(glob_flags, ECHO_FLAG))
  1554. X    print_more(" ECHO_FLAG");
  1555. X    if (ison(glob_flags, IS_GETTING))
  1556. X    print_more(" IS_GETTING");
  1557. X    if (ison(glob_flags, PRE_CURSES))
  1558. X    print_more(" PRE_CURSES");
  1559. X    if (ison(glob_flags, READ_ONLY  ))
  1560. X    print_more(" READ_ONLY");
  1561. X    if (ison(glob_flags, REDIRECT))
  1562. X    print_more(" REDIRECT");
  1563. X    if (ison(glob_flags, WAS_INTR ))
  1564. X    print_more(" WAS_INTR");
  1565. X    if (ison(glob_flags, WARNING   ))
  1566. X    print_more(" WARNING");
  1567. X    print_more("\n");
  1568. X}
  1569. X
  1570. Xis_spool(f)
  1571. Xregister char *f;
  1572. X{
  1573. X    return !strncmp(f, MAILDIR, strlen(MAILDIR));
  1574. X}
  1575. X
  1576. Xprint_argv(argv)
  1577. Xchar **argv;
  1578. X{
  1579. X    while (*argv)
  1580. X    if (debug)
  1581. X        printf("(%s) ", *argv++);
  1582. X    else
  1583. X        wprint("%s ", *argv++);
  1584. X    if (debug) {
  1585. X    putchar('\n');
  1586. X    fflush(stdout);
  1587. X    } else
  1588. X    wprint("\n");
  1589. X}
  1590. X
  1591. Xmsg_flags(c, v, list)
  1592. Xregister char **v, *list;
  1593. X{
  1594. X    register int    i;
  1595. X    register long    newflag = 0;
  1596. X
  1597. X    if (c && *++v && !strcmp(*v, "-?"))
  1598. X    return help(0, "msg_flags", cmd_help);
  1599. X    if (c && (c = get_msg_list(v, list)) == -1)
  1600. X    return -1;
  1601. X    if (v && *(v += (c-1))) {
  1602. X    turnon(glob_flags, DO_UPDATE);
  1603. X    while (*++v)
  1604. X        for (c = 0; v[0][c]; c++)
  1605. X        switch (lower(v[0][c])) {
  1606. X            case 'n' : turnon(newflag, UNREAD), turnoff(newflag, OLD);
  1607. X            when 'o' : turnon(newflag, OLD);
  1608. X            when 'r' : turnoff(newflag, UNREAD);
  1609. X            when 'd' : turnon(newflag, DELETE);
  1610. X            when 'p' : turnon(newflag, PRESERVE);
  1611. X            when 'u' : turnon(newflag, UNREAD);
  1612. X            otherwise: return help(0, "msg_flags", cmd_help);
  1613. X        }
  1614. X    }
  1615. X
  1616. X    for (i = 0; i < msg_cnt; i++) {
  1617. X    if (!msg_bit(list, i))
  1618. X        continue;
  1619. X    else if (!newflag) {
  1620. X        wprint("msg %d: offset: %d, lines: %d, bytes: %d, flags:", i+1,
  1621. X        msg[i].m_offset, msg[i].m_lines, msg[i].m_size);
  1622. X        if (ison(msg[i].m_flags, UNREAD))
  1623. X        wprint(" UNREAD");
  1624. X        if (ison(msg[i].m_flags, OLD))
  1625. X        wprint(" OLD");
  1626. X        if (ison(msg[i].m_flags, DELETE))
  1627. X        wprint(" DELETE");
  1628. X        if (ison(msg[i].m_flags, PRESERVE))
  1629. X        wprint(" PRESERVE");
  1630. X        if (ison(msg[i].m_flags, UPDATE_STATUS))
  1631. X        wprint(" UPDATE_STATUS");
  1632. X        wprint("\n");
  1633. X    } else
  1634. X        msg[i].m_flags = newflag;
  1635. X    }
  1636. X    return 0;
  1637. X}
  1638. END_OF_FILE
  1639. if test 21487 -ne `wc -c <'misc.c'`; then
  1640.     echo shar: \"'misc.c'\" unpacked with wrong size!
  1641. fi
  1642. # end of 'misc.c'
  1643. fi
  1644. echo shar: End of archive 7 \(of 12\).
  1645. cp /dev/null ark7isdone
  1646. MISSING=""
  1647. for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
  1648.     if test ! -f ark${I}isdone ; then
  1649.     MISSING="${MISSING} ${I}"
  1650.     fi
  1651. done
  1652. if test "${MISSING}" = "" ; then
  1653.     echo You have unpacked all 12 archives.
  1654.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1655. else
  1656.     echo You still need to unpack the following archives:
  1657.     echo "        " ${MISSING}
  1658. fi
  1659. ##  End of shell archive.
  1660. exit 0
  1661.